package com.ants.boot.utils;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * redis 工具类
 * @author 蚂蚁会花呗
 *
 */
@Component
public final class RedisUtils {
	
	
	@Autowired
	private RedisTemplate<String, Object> redisTemplate;
	
	/********************common公用***************************/
	/**
	 * 指定缓存失效时间，过期自动销毁
	 * @param key 键
	 * @param timeout 时间(秒)
	 * @return
	 */
	public boolean expire(String key,long timeout){
		keyIfNull(key);
		try {
			if (timeout>0) {
				redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	/**
	 * 根据key值 获取过期时间
	 * @param key 键，不能为null
	 * @return -1表示永久有效，-2表示该键不存在
	 * @throws Exception 
	 */
	public long getExpire(String key){
		keyIfNull(key);
		return redisTemplate.getExpire(key);
	}
	
	/**
	 * 判断key 是否存在
	 * @param key 键
	 * @return true 存在，false不存在
	 */
	public boolean hasKey(String key){
		keyIfNull(key);
		return redisTemplate.hasKey(key);
	}
	
	/**
	 * 删除缓存
	 * @param key 键 单个或者数组
	 */
	@SuppressWarnings("unchecked")
	public void delete(String... key){
		if (key != null && key.length > 0) {
			if (key.length == 1) {
				redisTemplate.delete(key[0]);
			}else {
				redisTemplate.delete( Arrays.asList(key));
			}
		}
	}
	/*************************String字符串缓存*******************************/
	/**
	 * 获取字符串缓存（普通缓存）
	 * @param key 键
	 * @return
	 */
	public Object get(String key){
		return key == null ? null : redisTemplate.opsForValue().get(key);
	}
	
	/**
	 * 设置普通缓存
	 * @param key 键
	 * @param value 值
	 * @return true成功， false 失败
	 */
	public boolean set(String key, Object value){
		try {
			redisTemplate.opsForValue().set(key, value);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		
	}
	
	/**
	 * 设置缓存，并设置过期时间 秒
	 * @param key 键
	 * @param value 值
	 * @param timeout 过期时间 秒
	 * @return true成功， false 失败
	 */
	public boolean set(String key, Object value,long timeout){
		try {
			if (timeout > 0) {
				redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
			}else {
				set(key, value);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	/**
	 * 递增或者递减，当delta大于零时递增，小于零时递减
	 * @param key
	 * @param delta
	 * @return 返回递增后的数字
	 */
	public long increment(String key,long delta){
		return redisTemplate.opsForValue().increment(key, delta);
	}
	
	/***********************list**************************/
	
	/**
	 * 获取list缓存的内容
	 * @param key 键
	 * @param start 开始索引 0
	 * @param end 结束索引  start=0 end=-1 表示获取所有值
	 * @return list对象
	 */
	public List<Object> listGet(String key,long start,long end){
		try {
			return redisTemplate.opsForList().range(key, start, end);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 * 获取List缓存的长度
	 * @param key 键
	 * @return list缓存数组长度
	 */
	public long listGetSize(String key){
		keyIfNull(key);
		try {
			return redisTemplate.opsForList().size(key);
		} catch (Exception e) {
			return 0;
		}
	}
	
	/**
	 * 通过索引 获取缓存list中的值
	 * @param key 键
	 * @param index 索引 index>=0 时 0是第一个元素，1是第二个元素， index<0时 -1 表示最后一个元素 -2倒数第二个
	 * @return 指定索引的值
	 */
	public Object listGetIndex(String key, long index){
		try {
			return redisTemplate.opsForList().index(key, index);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 * 将list 放入缓存
	 * @param key 键
	 * @param value 值
	 * @return
	 */
	public boolean rightPush(String key, Object value){
		try {
			redisTemplate.opsForList().rightPush(key, value);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	/**
	 * 将list 放入缓存并设置过期时间
	 * @param key 键
	 * @param value 值
	 * @param timeout 过期时间
	 * @return 成功返回 true 
	 */
	public boolean rightPush(String key,Object value,long timeout){
		try {
			boolean flag =  rightPush(key, value);
			if (timeout > 0) {
				expire(key, timeout);
			}
			return flag;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	/**
	 * 将List数组放入缓存
	 * @param key 键
	 * @param values list数组
	 * @return 成功返回true
	 */
	public boolean rightPushAll(String key,List<Object> values){
		try {
			redisTemplate.opsForList().rightPushAll(key, values);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	/**
	 * 将List数组放入缓存 并设置过期时间
	 * @param key 键
	 * @param values list数组
	 * @param timeout 过期时间
	 * @return
	 */
	public boolean rightPushAll(String key,List<Object> values, long timeout){
		try {
			redisTemplate.opsForList().rightPushAll(key, values);
			if (timeout > 0) 
				expire(key, timeout);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	/**
	 * 根据索引值修改list缓存中的某条数据
	 * @param key 键
	 * @param index 索引
	 * @param value 值
	 * @return 成功返回true
	 */
	public boolean listSetIndex(String key,long index,Object value){
		try {
			redisTemplate.opsForList().set(key, index, value);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	/**
	 * 移除多个value值
	 * @param key 键
	 * @param count 数量
	 * @param value 值
	 * @return 移除成功的个数
	 */
	public long listRemove(String key,long count, Object value){
		try {
			return redisTemplate.opsForList().remove(key, count, value).longValue();
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}
	
	/*******************************Map**********************************/
	/**
	 * hash get 
	 * @param key 不能为 null
	 * @param item 不能为null
	 * @return
	 */
	public Object hget(String key,String item){
		return redisTemplate.opsForHash().get(key, item);
	}
	
	/**
	 * 获取hashkey对应的所有键值
	 * @param key 键
	 * @return 对应的多个键值
	 */
	public Map<Object, Object> hmget(String key){
		return redisTemplate.opsForHash().entries(key);
	}
	
	/**
	 * hashSet 
	 * @param key 键
	 * @param map 值
	 * @return 成功返回true
	 */
	public boolean hmset(String key,Map<String, Object> map){
		try {
			redisTemplate.opsForHash().putAll(key, map);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	/**
	 *  hashSet 并设置过期时间
	 * @param key 键
	 * @param map 对应多个键值
	 * @param timeout 过期时间
	 * @return
	 */
	public boolean hmset(String key,Map<String, Object> map,long timeout){
		hmset(key, map);
		if (timeout > 0) {
			expire(key, timeout);
		}
		return false;
	}
	
	/**
	 * 向一张hash表中放入数据，如果不存在将创建
	 * @param key 键
	 * @param item 项
	 * @param value 值
	 * @return 成功返回true
	 */
	public boolean hset(String key,String item,Object value){
		try {
			redisTemplate.opsForHash().put(key, item, value);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	/**
	 * 向一张hash表中放入数据如果不存在将创建，并设置缓存过期时间
	 * @param key 键
	 * @param item 项
	 * @param value 值
	 * @param timeout 过期时间 秒
	 * @return 成功返回true
	 */
	public boolean hset(String key,String item,Object value,long timeout){
		hset(key, item, value);
		if (timeout > 0) {
			expire(key, timeout);
		}
		return false;
	}
	
	/**
	 * 删除hash表中的值
	 * @param key 键
	 * @param item 项，可以多个
	 */
	public void hdel(String key, Object... item){
		keyIfNull(key);
		redisTemplate.opsForHash().delete(key, item);
	}
	/**
	 * 判断hash表中是否有该项的值
	 * @param key 键 不能为空
	 * @param item 项
	 * @return true 存在
	 */
	public boolean hHasKey(String key,String item){
		keyIfNull(key);
		return redisTemplate.opsForHash().hasKey(key, item);
	}
	
	/***
	 * hash 递增递减 如果不存在，创建一个，并把递增或递减后的值返回
	 * @param key 键
	 * @param item 项
	 * @param delta 正长整型或者负长整型
	 * @return 递增递减后的值
	 */
	public double increment(String key,String item,double delta){
		return redisTemplate.opsForHash().increment(key, item, delta);
	}
	
	/*************************Set缓存********************************/
	
	/**
	 * 根据key值 获取 Set中所有的值
	 * @param key 键
	 * @return Set中所有的值
	 */
	public Set<Object> sGet(String key){
		try {
			return redisTemplate.opsForSet().members(key);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	/**
	 * 根据value从一个set中查询，是否存在
	 * @param key 键
	 * @param value 值
	 * @return true 存在
	 */
	public boolean sHasKey(String key,Object value){
		try {
			return redisTemplate.opsForSet().isMember(key, value);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	/**
	 * 将数据放入set缓存
	 * @param key 键
	 * @param values 值，可以是多个
	 * @return 返回成功个数
	 */
	public long sSet(String key, Object... values){
		try {
			return redisTemplate.opsForSet().add(key, values);
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}
	
	/**
	 * 将set数据放入缓存 并设置过期时间
	 * @param key 键
	 * @param timeout 过期时间
	 * @param values 值可以是多个
	 * @return 设置成功的个数
	 */
	public long sSetAndTime(String key, long timeout,Object... values){
		try {
			Long count = redisTemplate.opsForSet().add(key, values);
			if (timeout > 0) {
				expire(key, timeout);
			}
			return count;
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}
	
	/**
	 * 获取set的长度 
	 * @param key 键
	 * @return 长度
	 */
	public long sGetSetSize(String key){
		try {
			return redisTemplate.opsForSet().size(key);
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}
	
	/**
	 * 移除值为 value的缓存
	 * @param key 键
	 * @param values 值 多个
	 * @return 成功移除的个数
	 */
	public long setRemove(String key,Object... values){
		try {
			Long count = redisTemplate.opsForSet().remove(key, values);
			return count;
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}
	
	
	/**
	 * 判断 key值是否为空( null / 空白字符串)
	 * @param key
	 */
	private void keyIfNull(String key){
		if (StringUtils.isEmpty(key)) {
			throw new NullPointerException("key 键不能为空.....!");
		}
	}
	
	
	
	
}
